#include "log_printf.h"
#include <time.h>
#include <windows.h>

/* 定义日志级别名称数组 */
static const char *log_level_names[] = {
    "LIB  ERROR",
    "APP  ERROR",
    "APP NOTICE",
    "LIB NOTICE",
    "APP  TRACE",
    "LIB  TRACE"
};

/* 定义日志级别颜色数组 */
static const WORD log_level_colors[] = {
    FOREGROUND_RED | FOREGROUND_INTENSITY,           /* LOG_LIB_ERROR */
    FOREGROUND_RED | FOREGROUND_INTENSITY,           /* LOG_APP_ERROR */
    FOREGROUND_GREEN | FOREGROUND_INTENSITY,         /* LOG_APP_NOTICE */
    FOREGROUND_GREEN | FOREGROUND_INTENSITY,         /* LOG_LIB_NOTICE */
    FOREGROUND_BLUE | FOREGROUND_INTENSITY,          /* LOG_APP_TRACE */
    FOREGROUND_BLUE | FOREGROUND_INTENSITY           /* LOG_LIB_TRACE */
};

/* 当前日志级别，默认为应用程序错误级别 */
static LOG_LEVEL_T current_log_level = LOG_APP_ERROR;

/* 控制台句柄 */
static HANDLE hConsole = NULL;

/* 初始化控制台句柄 */
static void init_console(void) {
    if (hConsole == NULL) {
        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    }
}

/* 获取当前时间，格式为 yyyyMMdd hhmmss.毫秒 */
static void get_current_time(char* time_str, size_t size) {
    SYSTEMTIME st;
    GetLocalTime(&st);
    snprintf(time_str, size, "%04d%02d%02d %02d%02d%02d.%03d",
        st.wYear, st.wMonth, st.wDay,
        st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
}

/**
 * @brief 设置日志的打印级别
 *
 * @param log_level 要设置的日志级别
 */
void logPrintfSetLogLevel(LOG_LEVEL_T log_level) {
    if (log_level >= LOG_LIB_ERROR && log_level <= LOG_LIB_TRACE) {
        current_log_level = log_level;
    }
}

/**
 * @brief 设置日志的打印级别
 *
 * @param log_level_str "dummy/release/debug/develop/LOG_LIB_ERROR/.../LOG_LIB_TRACE"
 */
void logPrintfSetLogLevelByStr(const char *log_level_str) {
    if (log_level_str == NULL) {
        return;
    }

    if (strcmp(log_level_str, "dummy") == 0 || strcmp(log_level_str, "LOG_DUMMY") == 0) {
        current_log_level = LOG_DUMMY;
    } else if (strcmp(log_level_str, "release") == 0) {
        current_log_level = LOG_APP_ERROR;
    } else if (strcmp(log_level_str, "debug") == 0) {
        current_log_level = LOG_APP_TRACE;
    } else if (strcmp(log_level_str, "develop") == 0) {
        current_log_level = LOG_LIB_TRACE;
    } else if (strcmp(log_level_str, "LOG_LIB_ERROR") == 0) {
        current_log_level = LOG_LIB_ERROR;
    } else if (strcmp(log_level_str, "LOG_APP_ERROR") == 0) {
        current_log_level = LOG_APP_ERROR;
    } else if (strcmp(log_level_str, "LOG_APP_NOTICE") == 0) {
        current_log_level = LOG_APP_NOTICE;
    } else if (strcmp(log_level_str, "LOG_LIB_NOTICE") == 0) {
        current_log_level = LOG_LIB_NOTICE;
    } else if (strcmp(log_level_str, "LOG_APP_TRACE") == 0) {
        current_log_level = LOG_APP_TRACE;
    } else if (strcmp(log_level_str, "LOG_LIB_TRACE") == 0) {
        current_log_level = LOG_LIB_TRACE;
    }
}

/**
 * @brief 获取当前日志的打印级别
 *
 * @return LOG_LEVEL_T 当前日志级别
 */
LOG_LEVEL_T logPrintfGetLogLevel(void) {
    return current_log_level;
}

/**
 * @brief 打印格式化的日志信息
 *
 * @param log_level 日志级别
 * @param format 格式化字符串
 * @param ... 可变参数列表
 */
static void vlogPrintf(LOG_LEVEL_T log_level, const char *format, va_list args, int with_prompt) {
    if (log_level == LOG_DUMMY || log_level < LOG_LIB_ERROR || log_level > LOG_LIB_TRACE) {
        return;
    }

    if (log_level > current_log_level) {
        return;
    }

    init_console();

    /* 保存当前控制台属性 */
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    if (hConsole != NULL) {
        GetConsoleScreenBufferInfo(hConsole, &csbi);
    }

    //char time_str[26];
    //time_t now = time(NULL);

    //ctime_s(time_str, sizeof(time_str), &now);
    /* 移除换行符 */
    //time_str[24] = '\0';
    char time_str[32];
    get_current_time(time_str, sizeof(time_str));

    /* 设置控制台颜色 */
    if (hConsole != NULL) {
        SetConsoleTextAttribute(hConsole, log_level_colors[log_level]);
    }

    if (with_prompt) {
        /* 打印时间戳和日志级别 */
        printf("[%s] [%s] ", time_str, log_level_names[log_level]);
    }

    /* 打印日志内容 */
    vprintf(format, args);

    /* 恢复控制台属性 */
    if (hConsole != NULL) {
        SetConsoleTextAttribute(hConsole, csbi.wAttributes);
    }
}

/**
 * @brief 打印日志
 *
 * @param log_level 日志级别
 * @param format 格式化字符串
 * @param ... 可变参数列表
 */
void logPrintf(LOG_LEVEL_T log_level, const char *format, ...) {
    va_list args;
    va_start(args, format);
    vlogPrintf(log_level, format, args, 1);
    va_end(args);
}

/**
 * @brief 打印日志,不带前面提示的版本
 *
 * @param log_level 日志级别
 * @param format 格式化字符串
 * @param ... 可变参数列表
 */
void logPrintfNoPrompt(LOG_LEVEL_T log_level, const char *format, ...) {
    va_list args;
    va_start(args, format);
    vlogPrintf(log_level, format, args, 0);
    va_end(args);
}

/**
 * @brief 以十六进制形式打印内存区域内容
 *
 * @param log_level 日志级别
 * @param data 数据指针
 * @param len 数据长度
 */
void logPrintfHex(LOG_LEVEL_T log_level, const unsigned char *data, int len) {
    if (log_level == LOG_DUMMY || log_level < LOG_LIB_ERROR || log_level > LOG_LIB_TRACE) {
        return;
    }

    if (log_level > current_log_level) {
        return;
    }

    if (data == NULL || len <= 0) {
        return;
    }

    init_console();

    /* 保存当前控制台属性 */
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    if (hConsole != NULL) {
        GetConsoleScreenBufferInfo(hConsole, &csbi);
    }

    /* 设置控制台颜色 */
    if (hConsole != NULL) {
        SetConsoleTextAttribute(hConsole, log_level_colors[log_level]);
    }

    char time_str[26];
    time_t now = time(NULL);
    ctime_s(time_str, sizeof(time_str), &now);
    /* 移除换行符 */
    time_str[24] = '\0';

    /* 打印时间戳和日志级别 */
    printf("[%s] [%s] Hex dump of %d bytes at %p:\n", 
           time_str, log_level_names[log_level], len, data);

    int i, j;
    for (i = 0; i < len; i += 16) {
        /* 打印偏移量 */
        printf("%08x: ", i);

        /* 打印十六进制数据 */
        for (j = 0; j < 16; j++) {
            if (i + j < len) {
                printf("%02x ", data[i + j]);
            } else {
                printf("   ");
            }
        }

        printf(" ");

        /* 打印ASCII字符 */
        for (j = 0; j < 16; j++) {
            if (i + j < len) {
                char c = data[i + j];
                printf("%c", (c >= 32 && c <= 126) ? c : '.');
            }
        }

        printf("\n");
    }

    /* 恢复控制台属性 */
    if (hConsole != NULL) {
        SetConsoleTextAttribute(hConsole, csbi.wAttributes);
    }
}    